package com.harmony.pilot.knowledge.analyzer;

import com.harmony.pilot.knowledge.entity.CallRelation;
import com.harmony.pilot.knowledge.entity.FunctionDetail;
import com.harmony.pilot.knowledge.repository.FunctionDetailRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 调用图分析器
 * 分析函数间的调用关系，识别跨仓依赖
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class CallGraphAnalyzer {
    
    private final FunctionDetailRepository functionDetailRepository;
    
    // C++关键字和控制结构
    private static final Set<String> CPP_KEYWORDS = new HashSet<>(Arrays.asList(
        "if", "else", "for", "while", "do", "switch", "case", "return",
        "break", "continue", "goto", "try", "catch", "throw",
        "new", "delete", "sizeof", "typeof", "static_cast", "dynamic_cast",
        "const_cast", "reinterpret_cast"
    ));
    
    /**
     * 分析函数的调用关系
     */
    public List<CallRelation> analyzeFunction(FunctionDetail function, String filePath, String repo) {
        List<CallRelation> relations = new ArrayList<>();
        
        if (function.getFunctionBody() == null) {
            return relations;
        }
        
        // 1. 提取函数调用
        List<FunctionCall> calls = extractFunctionCalls(function.getFunctionBody());
        
        for (FunctionCall call : calls) {
            CallRelation relation = new CallRelation();
            
            // 设置调用者信息
            relation.setCallerSnippetId(function.getSnippetId());
            relation.setCallerName(function.getFunctionName());
            relation.setCallerFile(filePath);
            relation.setCallerRepo(repo);
            relation.setCallerModule(extractModuleName(filePath));
            
            // 设置被调用者信息
            relation.setCalleeName(call.getName());
            relation.setCallLine(call.getLine());
            relation.setCallContext(call.getContext());
            relation.setCallType(call.getType());
            
            // 2. 查找被调用函数的定义
            FunctionDetail callee = findFunctionDefinition(call.getName());
            
            if (callee != null) {
                // 找到了定义，内部函数
                relation.setCalleeSnippetId(callee.getSnippetId());
                relation.setCalleeFile(callee.getFilePath());
                relation.setCalleeRepo(callee.getRepo());
                relation.setCalleeModule(extractModuleName(callee.getFilePath()));
                relation.setIsExternal(false);
                
                // 判断是否跨仓/跨模块
                relation.setIsCrossRepo(!repo.equals(callee.getRepo()));
                relation.setIsCrossModule(!relation.getCallerModule().equals(relation.getCalleeModule()));
                
                relation.setConfidence(95);  // 高置信度
            } else {
                // 未找到定义，可能是外部依赖
                relation.setCalleeRepo("EXTERNAL");
                relation.setIsExternal(true);
                relation.setIsCrossRepo(true);
                
                // 3. 尝试从include中推断来源
                String declaredIn = findDeclaration(call.getName(), function.getIncludes());
                if (declaredIn != null) {
                    relation.setDeclaredIn(declaredIn);
                    relation.setCalleeRepo(inferRepoFromInclude(declaredIn));
                    relation.setIsInnerAPI(isInnerAPI(declaredIn));
                    relation.setConfidence(70);  // 中等置信度
                } else {
                    relation.setConfidence(50);  // 低置信度
                }
            }
            
            relations.add(relation);
        }
        
        return relations;
    }
    
    /**
     * 从函数体中提取函数调用
     */
    private List<FunctionCall> extractFunctionCalls(String functionBody) {
        List<FunctionCall> calls = new ArrayList<>();
        
        // 匹配函数调用：functionName(args)
        // 支持：普通调用、成员调用、指针调用
        Pattern pattern = Pattern.compile(
            "(?:[a-zA-Z_][a-zA-Z0-9_]*(?:\\.|->))?([a-zA-Z_][a-zA-Z0-9_]*)\\s*\\("
        );
        
        String[] lines = functionBody.split("\n");
        for (int i = 0; i < lines.length; i++) {
            String line = lines[i];
            
            // 跳过注释行
            if (line.trim().startsWith("//") || line.trim().startsWith("/*")) {
                continue;
            }
            
            Matcher matcher = pattern.matcher(line);
            while (matcher.find()) {
                String functionName = matcher.group(1);
                
                // 过滤关键字
                if (CPP_KEYWORDS.contains(functionName)) {
                    continue;
                }
                
                FunctionCall call = new FunctionCall();
                call.setName(functionName);
                call.setLine(i + 1);
                call.setContext(line.trim());
                
                // 判断调用类型
                if (line.contains("->")) {
                    call.setType("POINTER");
                } else if (line.contains(".")) {
                    call.setType("MEMBER");
                } else {
                    call.setType("DIRECT");
                }
                
                calls.add(call);
            }
        }
        
        return calls;
    }
    
    /**
     * 查找函数定义
     */
    private FunctionDetail findFunctionDefinition(String functionName) {
        // 精确匹配
        List<FunctionDetail> results = functionDetailRepository
            .findByFunctionNameContaining(functionName);
        
        if (results.isEmpty()) {
            return null;
        }
        
        // 如果有多个结果，优先返回完全匹配的
        for (FunctionDetail func : results) {
            if (func.getFunctionName().equals(functionName)) {
                return func;
            }
        }
        
        return results.get(0);  // 返回第一个模糊匹配的
    }
    
    /**
     * 从include中查找声明
     */
    private String findDeclaration(String functionName, String includes) {
        if (includes == null) {
            return null;
        }
        
        // includes是JSON数组：["iostream", "vector", "inner_api.h"]
        // 这里简化处理，实际需要解析JSON
        if (includes.contains("inner_api")) {
            return "inner_api.h";
        }
        
        // TODO: 完整的include解析
        return null;
    }
    
    /**
     * 从include路径推断仓库
     */
    private String inferRepoFromInclude(String includeFile) {
        if (includeFile.contains("foundation/")) {
            return extractRepoPath(includeFile, "foundation/");
        } else if (includeFile.contains("commonlibrary/")) {
            return extractRepoPath(includeFile, "commonlibrary/");
        } else if (includeFile.contains("base/")) {
            return extractRepoPath(includeFile, "base/");
        }
        
        return "EXTERNAL";
    }
    
    /**
     * 提取仓库路径
     */
    private String extractRepoPath(String path, String prefix) {
        int start = path.indexOf(prefix);
        if (start == -1) {
            return "UNKNOWN";
        }
        
        String subPath = path.substring(start);
        String[] parts = subPath.split("/");
        
        if (parts.length >= 2) {
            return parts[0] + "/" + parts[1];  // 例如: foundation/arkui
        }
        
        return "UNKNOWN";
    }
    
    /**
     * 判断是否是inner API
     */
    private boolean isInnerAPI(String headerFile) {
        if (headerFile == null) {
            return false;
        }
        
        return headerFile.contains("/inner_api/") ||
               headerFile.contains("/inner_kits/") ||
               headerFile.contains("_inner.h") ||
               headerFile.matches(".*inner.*\\.h$");
    }
    
    /**
     * 从文件路径提取模块名
     */
    private String extractModuleName(String filePath) {
        if (filePath == null) {
            return "UNKNOWN";
        }
        
        // foundation/arkui/napi/napi_common.cpp -> arkui
        String[] parts = filePath.split("/");
        if (parts.length >= 2) {
            return parts[1];
        }
        
        return "UNKNOWN";
    }
    
    /**
     * 内部类：函数调用信息
     */
    @lombok.Data
    private static class FunctionCall {
        private String name;      // 函数名
        private int line;         // 行号
        private String context;   // 上下文
        private String type;      // 调用类型：DIRECT, POINTER, MEMBER
    }
}

